package com.twd.nio;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set;

public class NioServer {

    // 服务端通道
    private ServerSocketChannel serverChannel;

    // 选择器
    private Selector selector;

    // 默认服务绑定端口
    private static int DEFAULT_BIND_PORT = 9000;

    public NioServer(int port) {
        initServer(port);
    }

    private void initServer(int port) {
        try {
            // 开启一个服务通道
            this.serverChannel = ServerSocketChannel.open();
            // 将通道绑定到指定端口
            this.serverChannel.bind( (port < 1 || port > 65535) ?
                    new InetSocketAddress(DEFAULT_BIND_PORT) :
                    new InetSocketAddress(port));
            // 将通道设置为非阻塞模式
            this.serverChannel.configureBlocking(false);
            // 打开一个 IO 监视器：Selector
            this.selector = Selector.open();
            // 将服务通道注册到 Selector 上，并在服务端通道注册 OP_ACCEPT 事件
            this.serverChannel.register(this.selector, SelectionKey.OP_ACCEPT);
        } catch (IOException ioException) {
            ioException.printStackTrace();
            System.out.println("init exception: " + ioException);
        }
    }

    public void startServer() throws InterruptedException {
        while (true){
            System.out.println("Selector开始监听-------------------");
            try {
                int ioEventCount = this.selector.select();
                System.out.println("Selector 检测到事件");
            } catch (IOException ioException) {
                ioException.printStackTrace();
                break;
            }
            Set<SelectionKey> selectionKeys = selector.selectedKeys();
            Iterator<SelectionKey> iterator = selectionKeys.iterator();

            while (iterator.hasNext()){
                SelectionKey key = iterator.next();
                //删除selectionKey
                iterator.remove();
                try {
                    if (key.isAcceptable()) {
                        System.out.println("执行连接操作");
                        ServerSocketChannel server = (ServerSocketChannel) key.channel();

                        // 接受客户端连接
                        SocketChannel client = server.accept();
                        client.configureBlocking(false); // 设置客户端通道非阻塞
                        // 为客户端通道注册读事件
                        client.register(selector, SelectionKey.OP_READ, ByteBuffer.allocate(1024));
                    }
                    // 可读数据
                    if (key.isReadable()) {
                        System.out.println("执行读操作");
                        SocketChannel client = (SocketChannel) key.channel();
                        ByteBuffer output = (ByteBuffer) key.attachment();
                        int read = client.read(output);
                        System.out.println("message : " + output.toString() + "-->" + new String(output.array(),0,read));
                    }
                    // 可写数据
                   else if (key.isWritable()) {
                        System.out.println("执行写操作");
                        SocketChannel client = (SocketChannel) key.channel();
                        ByteBuffer output = (ByteBuffer) key.attachment();
                        //转为读模式
                        output.flip();
                        client.write(output);
                        //销毁当前key
                        key.cancel();
                    }
                } catch (IOException ioException) {
                    ioException.printStackTrace();
                }

            }
            System.out.println("IO事件结束-------------------");
        }
    }

    public static void main(String[] args) throws InterruptedException {
        NioServer nioServer = new NioServer(DEFAULT_BIND_PORT);
        nioServer.startServer();
    }
}

